package Java8新特性;

import org.junit.Test;

import java.util.Comparator;
import java.util.function.Consumer;

/*
    Lambda 是一个匿名函数,可以把 Lambda 表达式理解为是一段可以传递的代码(将代码像数据一样进行传递),使用它可以写出更简洁、更灵活的代码
       语法:
             Lambda 表达式:在Java 8 语言中引入的一种新的语法元素和操作符,这个操作符为 "->",该操作符被称为 Lambda 操作符或箭头操作符,它将 Lambda 分为两个部分:
                左侧:指定了 Lambda 表达式需要的参数列表,其实就是接口中的抽象方法的形参列表
                右侧:指定了 Lambda 体,是抽象方法的实现逻辑,即 Lambda 表达式要执行的功能(其实就是重写的抽象方法的方法体)
       本质:
            作为函数式接口的实例(Lambda一定是借助于函数式接口而存在的,否则没有意义),即Lambda表达式如果想用,则一定要依赖于函数式接口
            函数式接口:
                如果一个接口中,只声明了一个抽象方法,则此接口就称为函数式接口
       举例:
            语法格式一:无参,无返回值
                Runnable runnable = () -> System.out.println("苏州大学");
            语法格式二:Lambda 需要一个参数,但是没有返回值
                Consumer<String> con = (String str) -> {System.out.println(str);};
            语法格式三:数据类型可以省略,因为可由编译器推断得出,称为"类型推断"
                Consumer<String> con = (str) -> {System.out.println(str);};
            语法格式四:Lambda 若只需要一个参数时,参数的小括号可以省略
                Consumer<String> con = str -> {System.out.println(str);};
            语法格式五:Lambda 需要两个或以上的参数,多条执行语句,并且可以有返回值
                Comparator<Integer> com = (x,y) ->{
                    System.out.println("实现函数式接口方法!");
                    return Integer.compare(x,y);
                };
            语法格式六:当 Lambda 体只有一条语句时,return 与大括号若有,都可以省略
                Comparator<Integer> com = (o1,o2) -> Integer.compare(o1,o2);

       类型推断:
             Lambda 表达式中的参数类型都是由编译器推断得出的,Lambda 表达式中无需指定类型,程序依然可以编译,这是因为 javac 根据程序的上下文,在后台推断出了参数的类型,Lambda 表达式的类型依赖于上下文环境,是由编译器推断出来的,这就是所谓的"类型推断"

       总结:
           左边:Lambda形参列表的参数类型可以省略,如果Lambda形参列表只有一个参数,则一对"()"也可以省略,但若有多个参数,小括号则不能省略
           右边:Lambda体应该使用一对大括号进行包裹,但如果Lambda体只有一条执行语句(可能是return语句),那么可以省略这一对大括号和return关键字
 */
public class Lambda01 {

    //语法格式一:无参,无返回值
    @Test
    public void test1(){
        //原始写法
        Runnable run1= new Runnable() {
            @Override
            public void run() {
                System.out.println("苏州大学");
            }
        };
        run1.run();

        //Lambda写法
        Runnable run2 = () -> {
            System.out.println("苏州大学");
        };
        run2.run();
    }

    //语法格式二:Lambda 需要一个参数,但是没有返回值
    @Test
    public void test2(){
        //原始写法
        Consumer<String> con1 = new Consumer<String>() {
            @Override
            public void accept(String s) {
                System.out.println(s);
            }
        };
        con1.accept("苏州大学");

        //Lambda写法
        Consumer<String> con2 = (String str) -> {
            System.out.println(str);
        };
        con2.accept("苏州大学");
    }

    //语法格式三:数据类型可以省略,因为可由编译器推断得出,称为"类型推断"
    @Test
    public void test3(){
        //优化前
        Consumer<String> con1 = (String str) -> {
            System.out.println(str);
        };
        con1.accept("苏州大学");

        //优化后
        Consumer<String> con2 = (str) -> {
            System.out.println(str);
        };
        con2.accept("苏州大学");
    }

    //语法格式四:Lambda 若只需要一个参数时,参数的小括号可以省略
    @Test
    public void test4(){
        //优化前
        Consumer<String> con1 = (str) -> {
            System.out.println(str);
        };
        con1.accept("苏州大学");

        //优化后
        Consumer<String> con2 = str -> {
            System.out.println(str);
        };
        con2.accept("苏州大学");
    }

    //语法格式五:Lambda 需要两个或以上的参数,多条执行语句,并且可以有返回值
    @Test
    public void test5(){
        //原始写法
        Comparator<Integer> com1 = new Comparator<Integer>() {
            @Override
            public int compare(Integer o1, Integer o2) {
                System.out.println(o1);
                System.out.println(o2);
                return o1.compareTo(o2);
            }
        };
        System.out.println(com1.compare(12,21));

        //Lambda写法
        Comparator<Integer> com2 = (o1,o2) -> {
            System.out.println(o1);
            System.out.println(o2);
            return o1.compareTo(o2);
        };
        System.out.println(com2.compare(12,21));
    }

    //语法格式六:当 Lambda 体只有一条语句时,return 与大括号若有,都可以省略
    @Test
    public void test6(){
        //优化前
        Comparator<Integer> com1 = (o1,o2) -> {
            return o1.compareTo(o2);
        };
        System.out.println(com1.compare(12,21));

        //优化后
        Comparator<Integer> com2 = (o1,o2) -> o1.compareTo(o2);
        System.out.println(com1.compare(12,21));
    }

    @Test
    public void test7(){
        //优化前
        Consumer<String> con1 = str -> {
            System.out.println(str);
        };
        con1.accept("苏州大学");

        //优化后
        Consumer<String> con2 = str ->  System.out.println(str);
        con2.accept("苏州大学");
    }
}

//自定义函数式接口
@FunctionalInterface   //不加该注解也是一个函数式接口,但加上以后可以进行验证,当有多个抽象方法时会报错
interface MyInterface{

    void method1();

}
